package cn.actoncode.boot.framework.security.core.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.Claim;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;

import java.util.Calendar;
import java.util.Date;

@Slf4j
public class JwtUtil {

    /**
     * 生成JwtToken
     *
     * @param userId 用户id
     * @param secret 秘钥
     * @param amount 过期小时数
     */
    public static String getToken(Long userId, Integer userType, Long llts, String secret, int amount) {
        // 过期时间
        Calendar ca = Calendar.getInstance();
        ca.add(Calendar.HOUR, amount);

        // 随机Claim
        String random = RandomStringUtils.randomAlphabetic(6);

        // 创建JwtToken对象
        String token = "";
        token = JWT.create()
                // 用id
                .withSubject(userId.toString())
                // 发布时间
                .withIssuedAt(new Date())
                // 过期时间
                .withExpiresAt(ca.getTime())
                // 自定义随机Claim
                .withClaim("ran", random)
                .withClaim("type", userType)
                .withClaim("llts", llts)
                .sign(getSecret(secret, random));

        return token;
    }

    /**
     * 验证JwtToken
     *
     * @param token JwtToken数据
     * @return true 验证通过
     * @throws TokenExpiredException    Token过期
     * @throws JWTVerificationException 令牌无效（验证不通过）
     */
    public static void verifyToken(String token, String secret) throws TokenExpiredException, JWTVerificationException {
        String ran = JWT.decode(token).getClaim("ran").asString();
        JWTVerifier jwtVerifier = JWT.require(getSecret(secret, ran)).build();
        jwtVerifier.verify(token);
    }

    /**
     * 获取token中的声明
     *
     * @param token JwtToken数据
     **/
    public static String getSubject(String token) throws JWTDecodeException {
        return JWT.decode(token).getSubject();
    }

    /**
     * 获取token中的声明
     *
     * @param token JwtToken数据
     * @param claim
     **/
    public static Claim getClaim(String token, String claim) throws JWTDecodeException {
        return JWT.decode(token).getClaim(claim);
    }

    /**
     * 生成Secret混淆数据
     */
    private static Algorithm getSecret(String secret, String random) {
        String salt = "cn.actoncode.boot.framework.security";
        return Algorithm.HMAC256(secret + salt + random);
    }

}